package dao

import (
	"context"
	"sale-admin/config/mysql"
	"sale-admin/internal/dal"
	"sale-admin/internal/define"
	"sale-admin/internal/models"
	"sort"
	"strconv"
	"strings"
	"time"

	sharding "192.168.1.75/go-pkg/db-sharding"
	"192.168.1.75/go-pkg/helper"
	"github.com/golang-module/carbon/v2"
	"gorm.io/gen/field"
)

type FaceCount struct{}

type FaceCountList struct {
	Date       string  `json:"date"`
	YearWeek   string  `gorm:"-" json:"-"`
	RobotName  string  `json:"robot_name"`
	CurrHour   int     `json:"curr_hour"`
	FaceCount  float64 `json:"face_count"`
	FaceCount0 float64 `json:"face_count0"`
	FaceCount1 float64 `json:"face_count1"`
	FaceCount2 float64 `json:"face_count2"`
	FaceCount3 float64 `json:"face_count3"`
}

// 新增曝光量
func (FaceCount) Create(ctx context.Context, query *dal.Query, merchantID int64, robotName string,
	startTime, endTime, faceCount, faceCount0, faceCount1, faceCount2, faceCount3, areas3 int64) (err error) {
	m := query.MaAIServiceFaceCount
	dbs := sharding.GetDB(ctx, mysql.NewDB(), m.TableName(), startTime, startTime)
	queryDBTx := dal.Use(dbs.QueryDB).MaAIServiceFaceCount.WithContext(ctx)
	writeDBTx := dal.Use(dbs.WriteDB).MaAIServiceFaceCount.WithContext(ctx)
	updateDBTx := dal.Use(dbs.UpdateDB).MaAIServiceFaceCount.WithContext(ctx)

	var data models.MaAIServiceFaceCount
	data.MerchantID = merchantID
	data.RobotName = robotName
	data.StartTime = time.Unix(startTime, 0)
	data.EndTime = time.Unix(endTime, 0)
	data.FaceCount0 = faceCount0
	data.FaceCount1 = faceCount1
	data.FaceCount2 = faceCount2
	data.FaceCount3 = faceCount3
	data.Areas3 = areas3
	data.CreatedAt = time.Now().Unix()
	data.CreatedDate = time.Unix(startTime, 0)
	// 创建或更新
	count, _ := queryDBTx.Where(
		m.RobotName.Eq(robotName),
		m.StartTime.Eq(time.Unix(startTime, 0)),
		m.EndTime.Eq(time.Unix(endTime, 0)),
	).Count()
	// 未找到就创建
	if count <= 0 {
		data.ID, _ = helper.UUID{}.String()
		writeDBTx.Create(&data)
	} else {
		// 更新数据
		updateDBTx.Where(
			m.RobotName.Eq(robotName),
			m.StartTime.Eq(time.Unix(startTime, 0)),
			m.EndTime.Eq(time.Unix(endTime, 0)),
		).Updates(&data)
	}
	return
}

// 统计总数
type FaceCountTotal struct {
	FaceCount  float64 `json:"face_count"`
	FaceCount0 float64 `json:"face_count0"`
	FaceCount1 float64 `json:"face_count1"`
	FaceCount2 float64 `json:"face_count2"`
	FaceCount3 float64 `json:"face_count3"`
}

func (FaceCount) GetFaceCountTotal(ctx context.Context, query *dal.Query, merchantIDList []string,
	robotName, startTime, endTime string) (total FaceCountTotal) {
	if startTime == "" || endTime == "" {
		startTime = carbon.Now().StartOfDay().ToDateTimeString()
		endTime = carbon.Now().EndOfDay().ToDateTimeString()
	}
	m := query.MaAIServiceFaceCount
	dbs := sharding.GetDB(ctx, mysql.NewDB(), m.TableName(),
		carbon.Parse(startTime).Timestamp(),
		carbon.Parse(endTime).Timestamp(),
	)
	tx := dal.Use(dbs.QueryDB).MaAIServiceFaceCount.
		WithContext(ctx).
		Where(m.StartTime.Between(
			carbon.Parse(startTime).ToStdTime(), carbon.Parse(endTime).ToStdTime(),
		))

	if len(merchantIDList) > 0 {
		var merchants []int64
		for _, v := range merchantIDList {
			merchantID, _ := strconv.ParseInt(v, 10, 64)
			merchants = append(merchants, merchantID)
		}
		tx = tx.Where(m.MerchantID.In(merchants...))
	}
	if robotName != "" {
		tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
	}
	tx.Select(
		m.FaceCount0.Sum().As(m.FaceCount0.ColumnName().String()),
		m.FaceCount1.Sum().As(m.FaceCount1.ColumnName().String()),
		m.FaceCount2.Sum().As(m.FaceCount2.ColumnName().String()),
		m.FaceCount3.Sum().As(m.FaceCount3.ColumnName().String()),
	).
		Scan(&total)
	total.FaceCount = total.FaceCount0 + total.FaceCount1 + total.FaceCount2 + total.FaceCount3
	return
}

// 获取曝光量列表
// groupType 1时间	2时间+机器	3机器
func (FaceCount) GetFaceCountList(ctx context.Context, query *dal.Query, merchantIDList []string,
	robotName, startTime, endTime string, dateType, groupType, page, limit int) (
	res []FaceCountList, total int64,
) {
	if startTime == "" || endTime == "" {
		startTime = carbon.Now().StartOfDay().ToDateTimeString()
		endTime = carbon.Now().EndOfDay().ToDateTimeString()
	}
	var Result = []FaceCountList{}
	m := query.MaAIServiceFaceCount
	dbs := sharding.GetDB(ctx, mysql.NewDB(), m.TableName(),
		carbon.Parse(startTime).Timestamp(),
		carbon.Parse(endTime).Timestamp(),
	)
	tx := dal.Use(dbs.QueryDB).MaAIServiceFaceCount.
		WithContext(ctx)
	if dateType == define.DAY {
		tx = tx.Where(m.CreatedDate.Between(
			carbon.Parse(startTime).ToStdTime(),
			carbon.Parse(endTime).ToStdTime(),
		))
	} else {
		tx = tx.Where(m.StartTime.Between(
			carbon.Parse(startTime).ToStdTime(),
			carbon.Parse(endTime).ToStdTime(),
		))
	}
	if robotName != "" {
		tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
	}
	if len(merchantIDList) > 0 {
		var merchants []int64
		for _, v := range merchantIDList {
			merchantID, _ := strconv.ParseInt(v, 10, 64)
			merchants = append(merchants, merchantID)
		}
		tx = tx.Where(m.MerchantID.In(merchants...))
	}

	var groupField []field.Expr
	var orderField []field.Expr
	var dateField field.Expr
	if groupType != 3 {
		switch dateType {
		case define.HOUR:
			dateField = m.StartTime.DateFormat("%Y-%m-%d %H:00").As("date")
			groupField = []field.Expr{m.StartTime.Year(), m.StartTime.Month(), m.StartTime.Day(), m.StartTime.Hour()}
			orderField = []field.Expr{m.StartTime.Year().Desc(), m.StartTime.Month().Desc(), m.StartTime.Day().Desc(),
				m.StartTime.Hour().Desc()}
		case define.DAY:
			dateField = m.CreatedDate.Date().As("date")
			groupField = []field.Expr{m.CreatedDate}
			orderField = []field.Expr{m.CreatedDate.Desc()}
		case define.WEEK:
			dateField = m.CreatedDate.Date().As("date")
			groupField = []field.Expr{m.CreatedDate}
			orderField = []field.Expr{m.CreatedDate.Desc()}
		case define.MONTH:
			dateField = m.StartTime.DateFormat("%Y-%m").As("date")
			groupField = []field.Expr{m.StartTime.Year(), m.StartTime.Month()}
			orderField = []field.Expr{m.StartTime.Year().Desc(), m.StartTime.Month().Desc()}
		case define.YEAR:
			dateField = m.StartTime.DateFormat("%Y").As("date")
			groupField = []field.Expr{m.StartTime.Year()}
			orderField = []field.Expr{m.StartTime.Year().Desc()}
		default:
			return
		}
	}
	var group, order []field.Expr
	if groupType == 1 { // 时间
		group = groupField
		order = orderField
	} else if groupType == 2 { // 时间+机器
		group = append(groupField, m.RobotName)
		order = append(orderField, m.RobotName.Desc())
	} else if groupType == 3 { // 机器
		group = []field.Expr{m.RobotName}
		order = []field.Expr{m.RobotName.Desc()}
	}
	offset, limit := Offset(page, limit)
	if dateField != nil {
		total, _ = tx.Group(group...).
			Order(order...).
			Select(m.RobotName,
				m.FaceCount0.Sum().As(m.FaceCount0.ColumnName().String()),
				m.FaceCount1.Sum().As(m.FaceCount1.ColumnName().String()),
				m.FaceCount2.Sum().As(m.FaceCount2.ColumnName().String()),
				m.FaceCount3.Sum().As(m.FaceCount3.ColumnName().String()),
				dateField).
			ScanByPage(&Result, offset, limit)
	} else {
		total, _ = tx.Group(group...).
			Order(order...).
			Select(m.RobotName,
				m.FaceCount0.Sum().As(m.FaceCount0.ColumnName().String()),
				m.FaceCount1.Sum().As(m.FaceCount1.ColumnName().String()),
				m.FaceCount2.Sum().As(m.FaceCount2.ColumnName().String()),
				m.FaceCount3.Sum().As(m.FaceCount3.ColumnName().String()),
			).
			ScanByPage(&Result, offset, limit)
	}
	for k, v := range Result {
		Result[k].FaceCount = v.FaceCount0 + v.FaceCount1 + v.FaceCount2 + v.FaceCount3
	}
	return Result, total
}

// 获取机器单日曝光量
func (FaceCount) GetDailyFaceCount(ctx context.Context, query *dal.Query, robotName, date string) (
	res FaceCountList,
) {
	if robotName == "" || date == "" {
		return
	}
	m := query.MaAIServiceFaceCount
	dbs := sharding.GetDB(ctx, mysql.NewDB(), m.TableName(),
		carbon.Parse(date).Timestamp(),
		carbon.Parse(date).Timestamp(),
	)
	dal.Use(dbs.QueryDB).MaAIServiceFaceCount.
		WithContext(ctx).
		Where(m.RobotName.Eq(robotName)).
		Where(m.CreatedDate.Eq(carbon.ParseByLayout(date, carbon.DateLayout).ToStdTime())).
		Select(
			m.FaceCount0.Sum().As(m.FaceCount0.ColumnName().String()),
			m.FaceCount1.Sum().As(m.FaceCount1.ColumnName().String()),
			m.FaceCount2.Sum().As(m.FaceCount2.ColumnName().String()),
			m.FaceCount3.Sum().As(m.FaceCount3.ColumnName().String()),
		).Scan(&res)
	return
}

// 获取小时曝光量
func (FaceCount) GetHourFaceCount(ctx context.Context, query *dal.Query, merchantIDList []string,
	date, robotName string) (Res struct {
	FaceCount24       []FaceCountList
	FaceCount24Robots []FaceCountList
}) {
	if date == "" {
		date = carbon.Now().ToDateString()
	}
	startTime := carbon.Parse(date).StartOfDay().Timestamp()
	endTime := carbon.Parse(date).EndOfDay().Timestamp()

	m := query.MaAIServiceFaceCount
	dbs := sharding.GetDB(ctx, mysql.NewDB(), m.TableName(), startTime, endTime)
	tx := dal.Use(dbs.QueryDB).MaAIServiceFaceCount.
		WithContext(ctx).
		Where(m.CreatedDate.Eq(carbon.Parse(date).ToStdTime()))
	if len(merchantIDList) > 0 {
		var merchants []int64
		for _, v := range merchantIDList {
			merchantID, _ := strconv.ParseInt(v, 10, 64)
			merchants = append(merchants, merchantID)
		}
		tx = tx.Where(m.MerchantID.In(merchants...))
	}
	if robotName != "" {
		tx = tx.Where(m.RobotName.In(strings.Split(robotName, ",")...))
	}

	currHour := m.StartTime.DateFormat("%Y-%m-%d %H")
	fields := []field.Expr{
		m.CreatedDate.DateFormat("%Y-%m-%d").As("date"),
		currHour.As("curr_hour"),
		m.FaceCount0.Sum().As(m.FaceCount0.ColumnName().String()),
		m.FaceCount1.Sum().As(m.FaceCount1.ColumnName().String()),
		m.FaceCount2.Sum().As(m.FaceCount2.ColumnName().String()),
		m.FaceCount3.Sum().As(m.FaceCount3.ColumnName().String()),
	}
	group := []field.Expr{currHour}
	var Res1 = []FaceCountList{}
	tx.WithContext(ctx).
		Group(group...). // 按时统计
		Select(fields...).
		Order(currHour.Desc()).
		Scan(&Res1)

	fields = append(fields, m.RobotName)
	group = append(group, m.RobotName)
	var SalesFaceCountRes = []FaceCountList{}
	tx.WithContext(ctx).
		Group(group...). // 按时间 + 机器统计
		Select(fields...).
		Order(currHour). // 小时排序
		Scan(&SalesFaceCountRes)

	var HourCountRes1 = make(map[int]FaceCountList)
	for _, v := range Res1 {
		v.FaceCount = v.FaceCount0 + v.FaceCount1 + v.FaceCount2 + v.FaceCount3
		HourCountRes1[v.CurrHour] = v
	}
	for i := 0; i < 24; i++ {
		var item FaceCountList
		item.Date = date
		item.CurrHour = i
		if _, ok := HourCountRes1[i]; ok {
			item.FaceCount = HourCountRes1[i].FaceCount
			item.FaceCount0 = HourCountRes1[i].FaceCount0
			item.FaceCount1 = HourCountRes1[i].FaceCount1
			item.FaceCount2 = HourCountRes1[i].FaceCount2
			item.FaceCount3 = HourCountRes1[i].FaceCount3
		}
		Res.FaceCount24 = append(Res.FaceCount24, item)
	}
	var HourFaceCountMap = make(map[int]FaceCountList)
	for _, v := range SalesFaceCountRes {
		v.FaceCount = v.FaceCount0 + v.FaceCount1 + v.FaceCount2 + v.FaceCount3
		HourFaceCountMap[v.CurrHour] = v
	}
	for _, v := range HourFaceCountMap {
		Res.FaceCount24Robots = append(Res.FaceCount24Robots, v)
	}
	sort.Slice(Res.FaceCount24Robots, func(i, j int) bool {
		return Res.FaceCount24Robots[i].CurrHour < Res.FaceCount24Robots[j].CurrHour
	})
	return Res
}
